import os
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import rcParams

# 设置中文字体
rcParams['font.sans-serif'] = ['SimHei']

# 读取图片，0表示灰度图像
img = cv.imread('hanzi1.jpg', 0)
if img is None:
    print("无法读取图像，请检查路径是否正确")
    exit()

# 全局阈值处理
blur = cv.GaussianBlur(img, (5, 5), 0)  # 阈值处理的效果受噪声影响较大，常需要先进行滤波等预处理
_, th = cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
th1_inv = 255 - th

# 应用腐蚀操作
kernel1 = np.ones((3, 3), np.uint8)
eroded_img = cv.erode(th1_inv, kernel1, iterations=4)

# 应用膨胀操作
kernel2 = cv.getStructuringElement(cv.MORPH_CROSS, (4, 4)).astype(np.uint8)
dilated_img = cv.dilate(eroded_img, kernel2, iterations=8)
median_blurred = cv.medianBlur(dilated_img, 3)  # 中值滤波去除小白点

# 应用闭运算
kernel3 = np.ones((5, 5), np.uint8)
closed_img = cv.morphologyEx(median_blurred, cv.MORPH_CLOSE, kernel3, iterations=25)

# Canny边缘检测
img_blur = cv.GaussianBlur(closed_img, (3, 3), 0)  # 高斯滤波
canny = cv.Canny(img_blur, 100, 200)  # Canny边缘检测
contours, hierarchy = cv.findContours(canny, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)  # 查找轮廓
cv.drawContours(canny, contours, -1, (255), 2)  # 画边界框

# 选取汉字轮廓
# 轮廓检测
img_copy = th.copy()  # 复制图像以绘制边界框
valid_contours_indices = []  # 创建一个列表来存储通过周长筛选的轮廓索引
chars_folder = 'chars'
if not os.path.exists(chars_folder):
    os.makedirs(chars_folder)

for i, c in enumerate(contours):
    perimeter = cv.arcLength(c, True)
    print("轮廓周长：", perimeter)
    x, y, w, h = cv.boundingRect(c)
    # 根据周长阈值筛选并绘制边界框
    if perimeter > 350 and perimeter < 600:
        cv.rectangle(img_copy, (x, y), (x + w, y + h), (0, 255, 0), 2)
        valid_contours_indices.append(i)  # 将符合条件的轮廓索引添加到列表中

# 保存提取的字符
for i in valid_contours_indices:
    x, y, w, h = cv.boundingRect(contours[i])
    # 切割图像
    roi = th[y:y + h + 15, x:x + w + 15]
    # 创建文件保存路径
    filename = os.path.join(chars_folder, f'{i}.jpg')
    # 保存图像
    cv.imwrite(filename, roi)

# 显示原图灰度图像
plt.figure(figsize=(20, 15))  # 设置更大的图像尺寸
plt.subplot(3, 3, 1)
plt.imshow(img, 'gray')
plt.title("原图灰度图", fontsize=14)  # 增大字体大小
plt.axis('off')  # 隐藏坐标轴

# 显示颠倒后的阈值化图像
plt.subplot(3, 3, 2)
plt.imshow(th1_inv, 'gray')
plt.title("全局阈值处理>>二值化图像", fontsize=14)
plt.axis('off')  # 隐藏坐标轴

# 显示腐蚀后的图像
plt.subplot(3, 3, 3)
plt.imshow(eroded_img, 'gray')
plt.title("腐蚀操作>>去除噪点", fontsize=14)
plt.axis('off')  # 隐藏坐标轴

# 显示膨胀后的图像
plt.subplot(3, 3, 4)
plt.imshow(median_blurred, 'gray')
plt.title("膨胀操作>>中值滤波去除小白点", fontsize=14)
plt.axis('off')  # 隐藏坐标轴

# 显示闭运算后的图像
plt.subplot(3, 3, 5)
plt.imshow(closed_img, 'gray')
plt.title("闭运算>>填充闭合区域", fontsize=14)
plt.axis('off')  # 隐藏坐标轴

# 显示Canny边缘检测
plt.subplot(3, 3, 6)
plt.imshow(canny, 'gray')
plt.title("Canny边缘检测", fontsize=14)
plt.axis('off')  # 隐藏坐标轴

# 显示汉字轮廓
plt.subplot(3, 3, 7)
plt.imshow(img_copy, 'gray')
plt.title("汉字选中区域", fontsize=14)
plt.axis('off')  # 隐藏坐标轴
plt.tight_layout(pad=3.0)  # 增加子图之间的间距
plt.show()